package com.jgp.reporter;

import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.data.JRMapArrayDataSource;
import net.sf.jasperreports.engine.data.JRMapCollectionDataSource;
import net.sf.jasperreports.engine.export.HtmlExporter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.export.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.view.AbstractView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

/**
 * 项目   parent
 * 作者   loufei
 * 时间   2018/5/18
 */
@Component("jasper-multi-reporter")
public class MultiReporterView extends AbstractView {
    
    @Value("${jgp.reporter.dir:#{null}}")
    protected String reporterDir;

    @Override
    protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
                                           HttpServletResponse response) throws Exception {
    
        List<JasperPrint> jasperPrintList = new ArrayList();
        List<ReporterParam> params = (List<ReporterParam>)model.get("params");
        ReporterFormat format = (ReporterFormat) model.get("format");
        for (ReporterParam param : params) {
            Object data = param.getData();
            Map parameters =param.getParameters();
            String template =    param.getTplFileName();
            JRDataSource dataSource = getDataSource(data);
            InputStream stream  = Files.newInputStream(Paths.get(reporterDir, template + ".jrxml"));
            
            if(Objects.isNull(stream)){
                stream = getClass().getResourceAsStream("/jasper/" + template + ".jrxml");
            }
    
            JasperReport report = JasperCompileManager.compileReport(stream);
            JasperPrint jasperPrint = JasperFillManager.fillReport(report, parameters, dataSource);
            jasperPrintList.add(jasperPrint);
        }

        Map<String,Object> properties = new HashMap<>();
        properties.put("title",Objects.nonNull(model.get("title"))?model.get("title"):"");
        JRAbstractExporter exporter = null;
        switch (format) {
            case PDF:
                exporter = pdfExporter(properties,response);
                break;
            case HTML:
                exporter = htmlExporter(response);
                break;
        }
        if (Objects.nonNull(exporter)) {
            exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList));
            exporter.exportReport();
        }

    }


    private JRAbstractExporter htmlExporter(HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        JRAbstractExporter exporter = new HtmlExporter(DefaultJasperReportsContext.getInstance());
        exporter.setExporterOutput(new SimpleHtmlExporterOutput(response.getWriter()));
        return exporter;
    }

    private JRAbstractExporter pdfExporter(Map<String,Object> params,HttpServletResponse response) throws IOException {
        response.setContentType("application/pdf");
        JRAbstractExporter exporter = new JRPdfExporter(DefaultJasperReportsContext.getInstance());
        SimplePdfReportConfiguration reportConfig = new SimplePdfReportConfiguration();
        reportConfig.setSizePageToContent(true);
        reportConfig.setForceLineBreakPolicy(false);
        SimplePdfExporterConfiguration exportConfig = new SimplePdfExporterConfiguration();
        exportConfig.setMetadataTitle(params.get("title")+"");
        exporter.setConfiguration(reportConfig);
        exporter.setConfiguration(exportConfig);
        exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(response.getOutputStream()));
        return exporter;
    }


    private JRDataSource getDataSource(Object data) {

        JRDataSource dataSource = null;

        if (data instanceof Collection) {
            Collection collection = (Collection) data;
            if (collection.toArray()[0] instanceof Map) {
                dataSource = new JRMapCollectionDataSource(collection);
            } else {
                dataSource = new JRBeanCollectionDataSource(collection);
            }
        } else if (data instanceof Object[]) {
            dataSource = new JRMapArrayDataSource((Object[]) data);
        }

        return dataSource;
    }
}